package k.server;

import java.io.File;
import java.io.RandomAccessFile;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import k.db.DBConfig;
import k.db.DBUtils;
import k.util.FileUtil;

import org.apache.log4j.Logger;




public class Worker implements Runnable {

	private int sleepTime;
	
	private DBConfig dbconfig;
	
	private List<LogConfig> logConfigList ; 
	
	
	private Logger logger;

	/**
	 * 设置工作线程 sleep时间，单位
	 * @param sleepTime
	 */
	public void setSleepTime(int sleepTime) {
		this.sleepTime = sleepTime;
	}

	public void setDbconfig(DBConfig dbconfig) {
		this.dbconfig = dbconfig;
	}

	public void setLogConfigList(List<LogConfig> logConfig) {
		this.logConfigList = logConfig;
	}
	
	
	public boolean init()
	{
		logger = Logger.getLogger(Worker.class);
		
		//creat table ?
		
		return true;
	}
	
	/**
	 * @param lf
	 * @param lr
	 * @param outMap
	 * @return isFinish true 不需要继续读取该文件了，  false 需要继续读取读取该文件
	 * @throws Exception
	 */
	private boolean readFileByRegex(LogConfig lf,LogRunTime lr,Map<Integer,Map<Integer,String>> outMap) throws Exception
	{
				
		//检查文件
		File file = new File(lr.getFullFileNamePre() + lr.getFileNameEnd());
		if(!file.exists() || !file.isFile() || file.length() ==0)
		{
			logger.debug(lr.getFullFileNamePre() + lr.getFileNameEnd() + " is not exist");
			return true; 
		}
		Pattern pattern = Pattern.compile(lf.getPattern());
		
		RandomAccessFile reader = new RandomAccessFile(lr.getFullFileNamePre() + lr.getFileNameEnd(), "r");
		reader.seek(lr.getOffset());
		String tempString = null;
		int linenum = 0;
		
		
		
		boolean ret = true;
		
		while ((tempString = reader.readLine()) != null) {
			linenum++ ;
			
			//控制内存，每次读取最多不超过100条
			if(linenum==100)
			{
				ret = false;
				break;
			}
			
			if(tempString.equals("")){
				continue;
			}

			//字节流转成utf-8
			tempString = new String(tempString.getBytes("iso8859-1"),"UTF-8");

			Matcher matcher = pattern.matcher(tempString);
			//不匹配正则表达式
			if(!matcher.find())
			{
				//中间行
				if(reader.getFilePointer() < reader.length()-1)
				{
					logger.error("Can`t Match Reg FileName[" + lr.getFullFileNamePre() + lr.getFileNameEnd() +"] line: " + tempString);
					lr.setOffset(reader.getFilePointer());
					continue;
				//最后一行
				}else{									
					break;
				}
			}			
			
			//匹配
			Map<Integer, String> LineMap = new LinkedHashMap<Integer, String>();
			for (int i = 1; i <= matcher.groupCount(); i++) {
				LineMap.put(i, matcher.group(i));
			}
			
			outMap.put(linenum, LineMap);
			lr.setOffset(reader.getFilePointer());
		}
		
		reader.close();
		
		return ret;
	}
	
	
	private void exeonce () throws Exception 
	{
		String fileName = System.getProperty("user.dir") + File.separator
				+ "config" + File.separator + "map.txt";	
		
		Map<String,LogRunTime> map  = FileUtil.file2MapJSON(fileName);
		
		Date dNow = new Date(); // 当前时间
		SimpleDateFormat dateFm = new SimpleDateFormat("yyyyMMdd-HH");
		
		//读取所有文件
		for (LogConfig lc : logConfigList) {
			
			LogRunTime lrt = map.get(lc.getLogpath() + File.separator  +  lc.getFilenamepre());
			if(lrt == null)
			{
				lrt = initLogRunTime( dNow, dateFm, lc, lrt);
				map.put(lrt.getFullFileNamePre(), lrt);
				FileUtil.map2FileJSON(fileName,map);
			}
			//读取当前时间的文件
			if(lrt.getFileNameEnd().equals(dateFm.format(dNow)))
			{
				while(true)
				{
					long offset = lrt.getOffset();
					Map<Integer,Map<Integer,String>> outMap = new LinkedHashMap<Integer, Map<Integer,String>>();
					boolean isFinish = readFileByRegex(lc,lrt,outMap);
					if(outMap.isEmpty())
						break;
					DBUtils db = new DBUtils(); 
					db.getConnection(dbconfig.getUrl(), dbconfig.getUsername(), dbconfig.getPassword());
					//如果数据库存储错误，回滚文件偏移坐标
					try{
						db.batchInsert(lc, outMap);
					}catch(Exception e)
					{
						lrt.setOffset(offset);
						db.closeConnection();
						logger.error("file: " +lrt.getFullFileNamePre() + lrt.getFileNameEnd() + "sql: "+ lc.getSql(), e);
						return;
					}
					db.closeConnection();
					//每读完一次，并却入库都保存一下				
					FileUtil.map2FileJSON(fileName,map);
					if(isFinish)
						break;
				}
				
				continue;
			}
			
			//如果不是当前时间的文件，需要从记录的位置还是依次读取了
			while(true)
			{
				
				while(true)
				{
					long offset = lrt.getOffset();
					Map<Integer,Map<Integer,String>> outMap = new LinkedHashMap<Integer, Map<Integer,String>>();
					boolean isFinish = readFileByRegex(lc,lrt,outMap);
					if(outMap.isEmpty())
						break;
					DBUtils db = new DBUtils(); 
					db.getConnection(dbconfig.getUrl(), dbconfig.getUsername(), dbconfig.getPassword());
					//如果数据库存储错误，回滚文件偏移坐标
					try{
						db.batchInsert(lc, outMap);
					}catch(Exception e)
					{
						lrt.setOffset(offset);
						db.closeConnection();
						logger.error("file: " +lrt.getFullFileNamePre() + lrt.getFileNameEnd() + "sql: "+ lc.getSql(), e);
						return;
					}
					db.closeConnection();
					//每读完一次，并且入库都保存一下				
					FileUtil.map2FileJSON(fileName,map);
					if(isFinish)
						break;
				}
				
				
				Date date = dateFm.parse(lrt.getFileNameEnd());
				Calendar ca = Calendar.getInstance(); // 得到日历
				ca.setTime(date);// 把当前时间赋给日历
				ca.add(Calendar.HOUR_OF_DAY, 1); // 往后推迟1个小时
				date = ca.getTime(); // 得到前一天的时间
				lrt.setFileNameEnd(dateFm.format(date));
				lrt.setOffset(0);
				//每读完一次，并却入库都保存一下				
				FileUtil.map2FileJSON(fileName,map);
				//读到当前时间的文件，跳出循环
				if(lrt.getFileNameEnd().equals(dateFm.format(dNow)))
				{
					break;
				}
			}
					
		}
			
	}

	private LogRunTime initLogRunTime( Date dNow,
			SimpleDateFormat dateFm, LogConfig lc, LogRunTime lrt) {
		//如果发现是第一次运行，初始化

			String fullFileNamePre = lc.getLogpath() + File.separator + lc.getFilenamepre() ;
			lrt = new LogRunTime();
			lrt.setFullFileNamePre(fullFileNamePre);
			lrt.setFileNameEnd(dateFm.format(dNow));
			lrt.setOffset(0);
			

		return lrt;
	}
	
	

	@Override
	public void run() {
		
		if(!init())
		{
			return;
		}
		
		while(!isStop)
		{		
			try {
				exeonce();
				Thread.sleep(sleepTime);
			} catch (Exception e) {
				logger.error(e);
			}			
		}
		isStoped = true;
	}
	
	private boolean isStop = false;
	private boolean isStoped = false;
	
	public void stop_wait()
	{
		this.isStop = true;
		while(!isStoped)
		{
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

}
